tooling(pm): refuse --tier --residue in dispatch-gates instead of dropping the modifier - #15038
Merged
Merged
Conversation
…ropping the modifier `--residue` is read in exactly one place — the `derive(...)` call at the bottom of the direct-invocation block. The `--tier` branch beside that call never reaches it, so under `--tier` the flag was evaluated nowhere: exit 0, the tier verdict printed, and nothing on either stream saying the flag had been dropped. Adds one more arm to the refusal table that already holds `--ran --tier`, `--commands --json` and `--tier --commands` / `--tier --json`: exit 2, one line on stderr naming both flags. Ordered after the stdout-shape pair so `--tier --commands --residue` keeps the message it already had — this adds a refusal and rewords none. Pinned in `--self-test` with the control-plus-defect pair the card measured: the control (plain vs `--residue` on a real path differ when the derivation runs) is what makes the byte-identical `--tier` reading mean "the flag was dropped" rather than "the flag had nothing to add". Card #14753. Grep for callers passing both flags: zero, outside this file's own usage string. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
os-steve
marked this pull request as ready for review
September 3, 2026 18:33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #14753
--residueis read in exactly one place — thederive(...)call at the bottom of the direct-invocation block. The--tierbranch beside that call never reaches it, so under--tierthe flag was evaluated nowhere: exit 0, the tier verdict printed, and nothing on either stream saying the flag had been dropped.Triage (comment 5519196353) ruled the card's fork refuse and made the scope terminal: one more arm in the refusal table that already holds
--ran --tier,--commands --jsonand--tier --commands/--tier --json, exit 2, one line on stderr naming both flags, pinned with the card's control-plus-defect pair. That is exactly what this is — 53 added lines in one file, nothing removed, no other refusal, message or behaviour touched.The arm, and why it is its own arm rather than a widened condition
The
--tier --commands/--tier --jsonarm's message is--tier and X are two spellings of stdout — pass one.That sentence is false of--residue, which is not a spelling of stdout but a modifier of the derivation, so widening that arm's condition would have forced its message to become conditional and reworded — which the scope forbids. A siblingelse ifbeside it keeps that arm byte-identical and states the correct ground, which is the--ran --tierrefusal's, one flag over:--tierreads no workflow and no check script, so it derives no gate family — the same sentence that leaves a run record nothing to reconcile against leaves--residueno residue to list.Ordering. The new arm is placed AFTER the stdout-shape pair, for the reason that arm states about itself:
--tier --commands --residuekeeps the message it already had, so this branch adds a refusal and rewords none.--ran --tier --residuelikewise keeps the--ran --tiermessage from the arm above both.Readings — before and after, measured on this branch
Re-measured here rather than inherited from the card (the card measured at
7a17f3bf; this branch is off5d4d55ae, so the absolute byte counts differ and only the comparison carries). Target pathscripts/measure-partial-retirement-annotation.mjs, stdout bytes, exit codes captured before any pipe:5d4d55ae)2b453e5c)--residue--tier--tier --residue--residue--tiervs--tier --residueThe control is what makes the byte-identical reading mean anything: on its own, identical stdout is indistinguishable from "the flag had nothing to add here".
--residuegrows the derivation's own output by more than 3.6x when the derivation actually runs, and adds nothing at all under--tier.Three modes are unchanged to the byte. The only stderr delta on the unchanged runs was the banner's drift line (
origin/mainmoved under the worktree between the two measurements, the shared remote-tracking ref doing what AGENTS.md documents), not behaviour.Stop condition — the caller grep
Triage's stop condition: if refusing the pair breaks a real caller, refuse nothing and adjust nothing.
One hit, and it is not a caller: the file's own usage string,
scripts/pm/dispatch-gates.mjs:17937. The five repo-wide--tierinvocation sites (two skill files, one references file, this file's header example and that usage string) pass--residuenowhere. Zero callers — the stop condition does not fire.That usage line does state a grammar this change makes inaccurate for one pair. It is left alone under the terminal scope and filed instead: #15036.
Self-test pins, and the ablation
Added beside the
--tier --commands/--tier --jsonpins, in the block that already spawns the plain run on this same card:--residuechanges the derivation output when the derivation runs. Reuses the block's existinghumanOutas the plain side; a second spawn would be a full derivation of this tree to re-measure what that run already measured.--tier --residuerefuses: status 2 and empty stdout, because a refusal that still prints an answer is the bug wearing an exit code.--tierand--residue.Ablation. The arm was removed and the pins kept, on the committed tree, restore trap armed with absolute paths.
1 -> 0, arm-condition occurrences1 -> 0, new pins still present1, blob30d6e14b->e025b7b8(differs from the HEAD blob),node --checkclean.runCli->process.execPath [CLI]), so nothing resolves through a packageexportsor adist/that a stale build could green.dispatch-gates self-test: 2 of 1291 case(s) failed, and the two are exactly the new defect pins, naming themselves. The CONTROL stayed green in both legs — which is the point of having it.git status --porcelainempty,git diff HEADempty, worktree blob30d6e14b...equal toHEAD:scripts/pm/dispatch-gates.mjs.Verification — all at head
2b453e5cDerived from the real change set (no paths passed; the script reads its own merge base) with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands: 20 commands, identical to the dispatch's list. Exit codes captured by redirect before any pipe.check-ci-filter-parityOK: all 135 declared cross-package glob(s) (95 unique) are covered by core or crosspkg...check-closing-keyword-paritycheck-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators...)check-comment-mask-corpuscomment-mask corpus sweep: 5833 files, 0 disagree, 0 unparseable, 42.6scheck-cross-package-test-inputs(both spellings)OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.check-self-test-wiredevery one of the 166 script(s) CI runs that ship a --self-test has that self-test run by CI.check-shard-attestation2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).check-test-completenessPREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named.exit 3 — NOT MEASURED in the gate's own words, not a redcheck-whole-set-label-write0 violations — 252 file(s) over 3 root(s)...check:agent-test-spelling0 violations — 432 file(s) · 5850 bare -- token(s)...check:bash32-floor26 tracked shell file(s) ... name no bash 4+ construct(self-test 153 cases pass)check:cli-command-ids324 command-id literal(s) across 114 file(s) ... all resolve(self-test 39 cases pass)check:declared-population-live159 of 204 famil(ies) declare a path population, and every one of them reaches this tree's 8178 tracked file(s).check:entry-guard201 scripts/ file(s) — every entry guard goes through invoked-as.mjs(self-test 54 cases pass)check:nul-bytesOK (scanned 8171 text file(s) ... no raw ASCII control bytes).check:parse-guard200 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjs.(self-test 46 cases pass)check:pm-dispatch-gatesdispatch-gates self-test: 1291 cases pass.check:pnpm-filter-targets142/181 --filter occurrence(s) across 33 file(s) resolve against 79 workspace package(s)check:refd-timer-probe5828 source file(s) swept; the process-global timer probe is read in ... and nowhere else.check:watch-hint-literal48 declaration(s) across 4 rostered name(s) ... no unrostered spelling of the idiom in the tree.19 green, 1 NOT MEASURED (no red). Beyond the derived family:
node scripts/pm/dispatch-gates.mjs --self-test— 1291 cases pass, 0 failures, run in the foreground throughscripts/pm/os-verify-lock.sh(4m09s held, shared box).pnpm exec eslint . --no-inline-config --format json— 5833 files linted, 0 errors, 0 warnings, and the edited file is in that population (errors=0 warnings=0). No narrowing to declare.--self-testabove pluscheck:pm-dispatch-gates, which is what runs it. No vitest suite tests this script — the three*.test.tsfiles that mentiondispatch-gatesreference it in prose comments only (packages/cli/test/serve-node-env-production-default.e2e.test.ts,packages/create-objectstack/src/runtime-image.test.ts,packages/types/src/driver-error-classification.callers.test.ts).skip-changeset:scripts/pm/**publishes from no package.Not a governed surface:
node scripts/pm/check-governed-merges.mjs --test scripts/pm/dispatch-gates.mjsreturns 0 hits.Out-of-scope findings filed, unassigned: #15036 (the usage line above). #14880 and #14870 are not addressed here and remain open; #14294's pairs are untouched.
Generated by Claude Code